package ai.tuobot.sdk.impl


import ai.tuobot.app.BuildConfig
import ai.tuobot.sdk.inf.PlayCallB
import ai.tuobot.sdk.inf.TuoBotListener
import ai.tuobot.sdk.log.RLog
import ai.tuobot.sdk.model.AudioConfig
import ai.tuobot.sdk.model.BotState
import ai.tuobot.sdk.model.Character
import ai.tuobot.sdk.model.EventType
import ai.tuobot.sdk.model.LlmOption
import ai.tuobot.sdk.model.MsgMonitor
import ai.tuobot.sdk.model.MsgType
import ai.tuobot.sdk.model.TTSCmd
import ai.tuobot.sdk.model.TuobotEvent
import ai.tuobot.sdk.model.TuobotMsg
import ai.tuobot.sdk.model.WakeWords
import ai.tuobot.sdk.network.ApiExt
import ai.tuobot.sdk.network.CharacterApi
import ai.tuobot.sdk.network.SessionConfig
import ai.tuobot.sdk.network.WSConnection
import ai.tuobot.sdk.util.AudioRecorder
import ai.tuobot.sdk.util.AudioTrackPlayer
import ai.tuobot.sdk.util.BufferUtil
import ai.tuobot.sdk.util.ConfigToObj
import ai.tuobot.sdk.util.LocalSTT
import ai.tuobot.sdk.util.ProcessTextEvent
import ai.tuobot.sdk.util.WordsMatch
import android.content.Context
import android.media.AudioFormat
import android.media.MediaCodec
import android.media.MediaFormat
import android.media.MediaPlayer
import android.os.Build
import android.os.Bundle
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeoutOrNull
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okhttp3.ResponseBody
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import okio.ByteString
import org.json.JSONException
import org.json.JSONObject
import retrofit2.Call
import retrofit2.Callback
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream

internal class TuoBotAgentImpl(val context: Context, cfgStr: String?, private val character: Character, private val tuoBotListener: TuoBotListener) : WebSocketListener() {
    private var localSTT: LocalSTT
    private val TAG = "TuoBotAgentImpl"
    private val coroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())

    private var mediaCodec: MediaCodec? = null
    val audioTrackPlayer = AudioTrackPlayer()

    private val wsConnection = WSConnection(context, this)
    private var audioRecorder: AudioRecorder? = null
    private var cfgJson: JSONObject? = null

    private var bitRate = 48000 // 160000 48000
    private var sampleRate = 24000
    val language = character.language

    private val emptyBundle = Bundle()

    private var CURRENT_BOT_STATE = BotState.CLOSED

    private val job = SupervisorJob()
    private val scope = CoroutineScope(Dispatchers.IO + job)
    private lateinit var apiExt: ApiExt
    private var preSendFile: File? = null

    private var mediaPlayer: MediaPlayer? = null

    var previousCall: Call<ResponseBody>? = null

    lateinit var audioConfig: AudioConfig

    private var setedSampleRate = false
    init {
        try {
            cfgJson = cfgStr?.let { JSONObject(it) }

        } catch (e: JSONException) {
            e.printStackTrace()
            tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_PARAM_ERROR, emptyBundle))
        }

        // 初始化本地STT
        localSTT = LocalSTT(context)

        scope.launch {
            val res = localSTT.initModel()
            Log.d(TAG,"initModel : $res")
            if (res == LocalSTT.STATE_ERROR_UNPACK){
                tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_LOCAL_STT_ERROR, emptyBundle))
            }
            
            if (res == LocalSTT.STATE_READY){
                // 模型预热
                localSTT.preHot()
            }
        }


        // 连接webSocket
        connect()

        audioTrackPlayer.playFinish = object : PlayCallB {
            override fun playStart() {
                //RLog.d(TAG, "onEvent EVENT_AUDIO_PLAY_FINISH")
                tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_AUDIO_PLAY_START, emptyBundle))
            }

            override fun playFinish() {
                //RLog.d(TAG, "onEvent EVENT_AUDIO_PLAY_FINISH")
                tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_AUDIO_PLAY_FINISH, emptyBundle))
            }

        }
    }

    fun reConnect(){
        connect()
    }

    private fun connect() {
        cfgJson?.let {
            var useSearch = false
            var useQuivr = false
            var isJournalMode = false
            var llmModel = LlmOption.fromRaw("gpt-3.5-turbo-16k")
            var token = ""
            if (it.has("session")) {
                try {
                    val sessionObj = it.getJSONObject("session")
                    if (sessionObj.has("use_search"))
                        useSearch = sessionObj.getBoolean("use_search")
                    if (sessionObj.has("use_quivr"))
                        useQuivr = sessionObj.getBoolean("use_quivr")
                    if (sessionObj.has("is_journal_mode"))
                        isJournalMode = sessionObj.getBoolean("is_journal_mode")
                    if (sessionObj.has("llm_model"))
                        llmModel = LlmOption.fromRaw(sessionObj.getString("llm_model"))
                    if (sessionObj.has("token"))
                        token = sessionObj.getString("token")
                } catch (e: JSONException) {
                    tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_PARAM_ERROR, emptyBundle))
                }
            }

            val characterId = character.character_id

            var base_url = BuildConfig.WS_BASE_URL
            var base_http_url = BuildConfig.API_BASE_URL
            if (it.has("server")) {
                try {
                    val serverObj = it.getJSONObject("server")
                    if (serverObj.has("api_base")) {
                        val get_api_base = serverObj.getString("api_base")
                        if (get_api_base.isNotEmpty()) {
                            if (get_api_base.startsWith("https://"))
                                base_url = "wss://${get_api_base.removePrefix("https://")}"
                            if (get_api_base.startsWith("http://"))
                                base_url = "wss://${get_api_base.removePrefix("http://")}"

                            if (!((get_api_base.startsWith("https://") || get_api_base.startsWith("http://")))){
                                base_http_url = "https://${get_api_base}"
                            }else{
                                base_http_url = get_api_base
                            }

                        }
                    }
                } catch (e: JSONException) {
                    tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_PARAM_ERROR, emptyBundle))
                }
            }

            apiExt = ApiExt(base_http_url)

            llmModel?.let { it1 ->
                language?.let { it2 ->
                    characterId?.let { it3 ->
                        SessionConfig(
                            useSearch, useQuivr, isJournalMode,
                            it2, it1, it3, token
                        )
                    }
                }
            }?.let { it2 -> wsConnection.connect(it2, base_url) }

        }
    }

    override fun onOpen(webSocket: WebSocket, response: Response) {
        super.onOpen(webSocket, response)
        setedSampleRate = false

        CURRENT_BOT_STATE = BotState.SLEEPING

        prepareListen()
        startListen()

        val bundle = Bundle()
        bundle.putString("char_id", character.id)
        tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_CONNECTED, bundle))

        audioTrackPlayer.setAudioConfig(ConfigToObj.cfgJsonToAudioConfig(cfgJson))

        if (language?.contains("zh-CN") == true) {
            bitRate = 160000
        }

    }

    override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
        super.onFailure(webSocket, t, response)
        CURRENT_BOT_STATE = BotState.CLOSED

        val bundle = Bundle()
        tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_CONNECT_FAILURE, bundle))
    }

    override fun onMessage(webSocket: WebSocket, text: String) {
        RLog.d(TAG, "onEvent EVENT_TEXT EVENT_MESSAGE")
        super.onMessage(webSocket, text)
        val regex = Regex("""\[event\]:\s*(\[.*\])""")
        val matchResult = regex.find(text)
        if (matchResult != null) {
            val job = scope.launch{
                try {
                    val matchEventText = matchResult.groupValues[0]
                    RLog.d(TAG, "matchEventText "+matchEventText)
                    withTimeoutOrNull(1000L) {
                        val result = ProcessTextEvent.processEvent(matchEventText)
                        RLog.d(TAG, "result "+result)
                        handleEvent(result.first, result.second)
                        RLog.d(TAG, "handleEvent ")
                   }

                } catch (e: InterruptedException) {
                    e.printStackTrace()
                    RLog.d(TAG, "InterruptedException "+e.message)
                }catch (e: Exception) {
                    RLog.d(TAG, "Exception "+e.message)
                    e.printStackTrace()
                }

            }
            // 等待协程完成
            /*runBlocking {
                job.join()
            }*/
        }

        val bundle = Bundle()
        bundle.putString("text", text)
        tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_TEXT, bundle))


    }

    // 处理事件
    fun handleEvent(eventTypeStr: String, jsonObj: JSONObject) {
        RLog.d(TAG, "onEventCallB called with eventTypeStr: $eventTypeStr")
        when (eventTypeStr) {
            "sensitive_words" -> {
                // Handle sensitive_words event
            }

            "wake_up" -> {
                RLog.d(TAG, "Setting CURRENT_BOT_STATE to WAKE_UP, end_listen_silence_time:${audioConfig.end_listen_silence_time}")
                CURRENT_BOT_STATE = BotState.WAKE_UP
                audioRecorder?.setSilentceTimeDyn(audioConfig.end_listen_silence_time)
            }

            "nlp" -> {
                // Handle nlp event
            }

            "sleep" -> {
                CURRENT_BOT_STATE = BotState.SLEEPING
                RLog.d(TAG, "end_listen_silence_time:${audioConfig.end_listen_silence_time_of_wakeup}")
                audioRecorder?.setSilentceTimeDyn(audioConfig.end_listen_silence_time_of_wakeup)
            }

        }
    }

    override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
        super.onMessage(webSocket, bytes)
        val bundle = Bundle()
        bundle.putByteArray("bytes", bytes.toByteArray())

        Log.d("TimeStatistics","onMessage bytes")
        var autoPlay = true
        cfgJson?.let {
            if (it.has("audio")) {
                try {
                    val audioObj = it.getJSONObject("audio")
                    if (audioObj.has("auto_play"))
                        autoPlay = audioObj.getBoolean("auto_play")
                } catch (e: JSONException) {}
            }

        }

        //if (BotState.WAKE_UP ==  CURRENT_BOT_STATE )
            if (!autoPlay)
                tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_BYTE_ARRAY, bundle))
            else
                playMp3Audio(bytes.toByteArray())

        //playMp3Audio(bytes.toByteArray())
        //saveMp3DataToFile(bytes.toByteArray())
    }

    override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
        super.onClosed(webSocket, code, reason)
        CURRENT_BOT_STATE = BotState.CLOSED

        val bundle = Bundle()
        tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_CLOSED, bundle))

        audioTrackPlayer.releaseAudioTrack()
        releaseMediaCodec()
    }

    ////////////////////////////////////////////////////////////////////////////////////

    private fun resetMediaCodec() {
        try {
            mediaCodec?.stop()
            mediaCodec?.flush()
        } catch (e: IllegalStateException) {
            e.printStackTrace()
        }
    }

    private fun releaseMediaCodec() {
        if (mediaCodec!=null){
            // Ensure the MediaCodec is stopped and released properly
            try {
                mediaCodec?.stop()
            } catch (e: IllegalStateException) {
                e.printStackTrace()
            } finally {
                mediaCodec?.release()
            }
            mediaCodec = null
        }

    }

    private fun decodeAndPlayAudio(mp3Data: ByteArray) {
        RLog.d(TAG, "start decode")
        val bufferInfo = MediaCodec.BufferInfo()
        var offset = 0
        var endOfStream = false
        try {
            createMediaCodec()
            while (offset < mp3Data.size || !endOfStream) {
                val inputBufferIndex = mediaCodec?.dequeueInputBuffer(10000)?: -1
                if (inputBufferIndex >= 0) {
                    val inputBuffer = mediaCodec?.getInputBuffer(inputBufferIndex)
                    inputBuffer?.clear()

                    if (offset < mp3Data.size) {
                        val chunkSize = minOf(inputBuffer?.capacity() ?: 0, mp3Data.size - offset)
                        inputBuffer?.put(mp3Data, offset, chunkSize)
                        mediaCodec?.queueInputBuffer(inputBufferIndex, 0, chunkSize, 0, 0)
                        offset += chunkSize
                    } else {
                        // 发送流结束信号
                        mediaCodec?.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
                        endOfStream = true
                    }
                }

                var outputBufferIndex = mediaCodec ?. dequeueOutputBuffer (bufferInfo, 10000)?: -1
                RLog.d(TAG, "outputBufferIndex ${outputBufferIndex}")
                var retryTimes = 0
                while (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER && retryTimes < 10) {
                    Thread.sleep(10)
                    RLog.d(TAG, "MediaCodec.INFO_TRY_AGAIN_LATER")
                    outputBufferIndex = mediaCodec ?. dequeueOutputBuffer (bufferInfo, 10000)?: -1
                    retryTimes++
                }

                if (outputBufferIndex != null && outputBufferIndex >= 0) {
                    // 处理有效的输出缓冲区
                    val outputBuffer = mediaCodec?.getOutputBuffer(outputBufferIndex)
                    if (outputBuffer != null) {
                        val outData = ByteArray(bufferInfo.size)
                        outputBuffer.get(outData)
                        outputBuffer.clear()
                        RLog.d(TAG, "playAudio")
                        audioTrackPlayer.playAudio(outData)
                    }
                }

            }
        } catch (e: Exception) {
            e.printStackTrace()
            RLog.d(TAG, e.message.toString())
        } finally {
            releaseMediaCodec()
        }
        RLog.d(TAG, "end decode")
    }

    private fun saveMp3DataToFile(mp3Data: ByteArray) {
        context.let {
            val pcmFile = File(it.filesDir, "testzh.mp3")
            FileOutputStream(pcmFile).use { outputStream ->
                outputStream.write(mp3Data)
            }
        }

    }


    fun playMp3Audio(mp3Data: ByteArray) {
        //if ( CURRENT_BOT_STATE == BotState.WAKE_UP){
            coroutineScope.launch {
                var sampleRateR = 24000
                var bitRateR = 48000
                val paramsOfMp3 = BufferUtil.getPropertiesFromMp3Stream(context, mp3Data)
                sampleRateR = paramsOfMp3.first
                if (sampleRateR > 0){
                    sampleRate = sampleRateR
                }
                Log.d(TAG,"getSamplingRateFromMp3Stream : $sampleRate")

                bitRateR = paramsOfMp3.second
                if (bitRateR > 0){
                    bitRate = bitRateR
                }
                Log.d(TAG,"getSamplingRateFromMp3Stream : $bitRate")

                Log.d(TAG,"setedSampleRate : $setedSampleRate")

                if(!setedSampleRate && sampleRateR > 0){
                    audioTrackPlayer.setSampleRate(sampleRate)
                    audioTrackPlayer.createAudioTrack()
                    setedSampleRate = true
                    Log.d(TAG,"createAudioTrack : $sampleRate")
                }

                if (wsConnection.lastSessionInfo?.second?.language?.contains("zh-CN") == true) {
                    //audioTrackPlayer.playAudio(mp3Data)

                    // 播放音频
                    /*val audioFile = File(context.cacheDir, "ch_audio.mp3")
                    val outputStream = FileOutputStream(audioFile)
                    outputStream.write(mp3Data)
                    outputStream.close()

                    val mediaPlayer = MediaPlayer()
                    mediaPlayer.setDataSource(audioFile.absolutePath)
                    mediaPlayer.prepare()
                    mediaPlayer.start()

                    // 释放资源
                    mediaPlayer.setOnCompletionListener {
                        mediaPlayer.release()
                    }*/

                    decodeAndPlayAudio(mp3Data)

                    //saveMp3DataToFile(mp3Data)
                }
                else
                    decodeAndPlayAudio(mp3Data)
           }
        //}
    }


    private fun createMediaCodec() {
        mediaCodec = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_AUDIO_MPEG)
        val format = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_MPEG, sampleRate, 1)
        format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
        format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 1048576); // 设置输入缓冲区的最大大小 1048576(1MB)

        mediaCodec?.configure(format, null, null, 0)
        mediaCodec?.start()
    }

    fun sendMsg(tuobotMsg: TuobotMsg) {
        if (CURRENT_BOT_STATE == BotState.CLOSED){
            tuoBotListener.onEvent(
                TuobotEvent(
                    EventType.EVENT_SEND_ERROR_CLOSED,
                    emptyBundle
                )
            )
            return
        }
        when(tuobotMsg.msgType){
            MsgType.MSG_CHAT->{
                Log.d("TimeStatistics","sendMsg : ${tuobotMsg.bundle.getString("text")}")
                wsConnection.sendMsg(tuobotMsg.bundle.getString("text"))
            }

            /*MsgType.MSG_WAKE_UP -> {
                CURRENT_BOT_STATE = BotState.WAKE_UP
            }*/

            /*MsgType.MSG_SLEEP -> {
                CURRENT_BOT_STATE = BotState.SLEEPING

                val bundle = Bundle()
                bundle.putInt("status", 2)
                tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_LISTEN_STATUS, bundle))
            }*/

            MsgType.MSG_TTS -> {
                tuobotMsg.bundle.getString("text")?.let {
                    val ttsCmd = TTSCmd(character, it)
                    val ttsStr = ttsCmd.getNeedFormatedJsonStr()
                    val requestBody: RequestBody = ttsStr.toRequestBody("application/json".toMediaTypeOrNull())
                    // 取消上一次请求
                    previousCall?.cancel()
                    previousCall = apiExt.api(CharacterApi::class.java).tts(requestBody)
                    previousCall?.enqueue(object : Callback<ResponseBody> {
                        override fun onResponse(
                            call: Call<ResponseBody>,
                            response: retrofit2.Response<ResponseBody>
                        ) {
                            // 处理音频
                            response.body()?.let { responseBody ->
                                // 保存音频数据到文件
                                val audioFile = File(context.cacheDir, "tts_audio.mp4")
                                val outputStream = FileOutputStream(audioFile)
                                outputStream.write(responseBody.bytes())
                                outputStream.close()
                                playAudioFile(audioFile)
                            }
                        }

                        override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
                            RLog.d(TAG, "onFailure ${t.message}")
                            if (t.message.equals("Canceled") || t.message.equals("Socket closed") || t.message.equals("Socket is closed"))
                                return
                            tuoBotListener.onEvent(
                                TuobotEvent(
                                    EventType.EVENT_TTS_ERROR,
                                    emptyBundle
                                )
                            )
                        }

                    })

                }
            }
        }

    }

    fun sendAudioMsg(finishFile: File) {
        if (CURRENT_BOT_STATE == BotState.CLOSED){
            tuoBotListener.onEvent(
                TuobotEvent(
                    EventType.EVENT_SEND_ERROR_CLOSED,
                    emptyBundle
                )
            )
            return
        }
        Log.d("TimeStatistics","sendFile")
        wsConnection.sendFile(finishFile)

        preSendFile = finishFile
    }

    private fun prepareListen() {
        // 用户授予了权限，可以执行录音操作
        if (audioRecorder != null){
            audioRecorder?.stopRecording()
            audioRecorder = null
        }
        audioConfig = ConfigToObj.cfgJsonToAudioConfig(cfgJson);
        audioRecorder = AudioRecorder(
            context, audioConfig,{ status ->
                if (CURRENT_BOT_STATE == BotState.WAKE_UP){
                    val bundle = Bundle()
                    bundle.putInt("status",status)
                    tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_LISTEN_STATUS, bundle))

                    if (status == 0){ // 打断处理
                        var breakLLMSay = false
                        cfgJson?.let {
                            if (it.has("audio")) {
                                try {
                                    val audioObj = it.getJSONObject("audio")
                                    if (audioObj.has("break_llm_say"))
                                        breakLLMSay = audioObj.getBoolean("break_llm_say")
                                } catch (e: JSONException) {}
                            }

                        }
                        if (breakLLMSay){
                            audioTrackPlayer.clearAndPause()
                            /*val bundle2 = Bundle()
                                bundle2.putString("text","$")
                                sendMsg(TuobotMsg(MsgType.MSG_CHAT, bundle2))*/
                        }

                    }
                }

            },
            { finishFile ->
                preSendFile = finishFile
                recognizeOrSend(finishFile)
            })

    }

    private fun recognizeOrSend(finishFile: File) {
        if (CURRENT_BOT_STATE == BotState.SLEEPING) {
            if (localSTT.getCurrentState() != LocalSTT.STATE_READY) {
                tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_LOCAL_STT_ERROR, emptyBundle))
                return
            }

            scope.launch {
                FileInputStream(finishFile).use {
                    val recMapRes = localSTT.recognizeFile(it)
                    var matchWord = false
                    for (word in WakeWords.words) {
                        if (WordsMatch.matching(word.lowercase(), recMapRes)) {
                            CURRENT_BOT_STATE = BotState.WAKE_UP
                            val bundle = Bundle()
                            bundle.putString("text", MsgMonitor.monitorWakeUpMsg())
                            tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_TEXT, bundle))
                            Log.d(TAG, "Match Words " + recMapRes.toString())
                            matchWord = true
                            break
                        }
                    }
                    if (!matchWord) {
                        Log.d(TAG, "Not Match Words " + recMapRes.toString())
                    }
                    val bundle = Bundle()
                    bundle.putString("text", recMapRes.toString())
                    tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_LOCAL_STT_TEXT, bundle))
                }
            }
            return
        }

        //if ( CURRENT_BOT_STATE == BotState.WAKE_UP){
        RLog.e(TAG, "sendAudioMsg")
        sendAudioMsg(finishFile)
        //}
    }

    private fun startListen() {
        val res: Boolean? = audioRecorder?.startRecording()
        if (res != true) {
            RLog.e(TAG, "audioRecorder start false")
        }
    }

    fun disConnect(){
        wsConnection.closeConn()
    }

    fun destroy() {
        audioTrackPlayer.clearAndPause()
        audioRecorder?.stopRecording()
        audioRecorder = null
        disConnect()
        job.cancel()
        WakeWords.words.clear()
    }

    fun setMute(mute: Boolean) {
        audioRecorder?.setMute(mute)
    }

    fun reSendPreAudio() {
        preSendFile?.let {
            recognizeOrSend(it)
            Log.d(TAG, "reSendPreAudio:${it.absolutePath}")
        }
    }

    fun sendAudioFile(file:File){
        recognizeOrSend(file)
    }

    fun getLastAudioFile(): File? {
        return preSendFile
    }

    fun stopPlayAudio() {
        audioTrackPlayer.cancelPlayBackTime()
        audioTrackPlayer.clearAndPause()
        mediaPlayer?.stop()
        mediaPlayer?.release()
        mediaPlayer = null
    }

    fun sleep() {
        //wsConnection.sendMsg("[&Sleep]")
        CURRENT_BOT_STATE = BotState.SLEEPING
        val bundle = Bundle()
        bundle.putString("text", MsgMonitor.monitorSleepMsg())
        tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_TEXT, bundle))
    }

    fun playAudioFile(audioFile: File) {
        // 停止播放之前的声音
        stopPlayAudio()
        try {
            // 播放音频
            mediaPlayer = MediaPlayer()
            mediaPlayer?.setDataSource(audioFile.absolutePath)
            mediaPlayer?.prepare()
            mediaPlayer?.start()
            tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_AUDIO_PLAY_START, emptyBundle))
            // 释放资源
            mediaPlayer?.setOnCompletionListener {
                RLog.d(TAG, "onEvent EVENT_AUDIO_PLAY_FINISH")
                tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_AUDIO_PLAY_FINISH, emptyBundle))
                mediaPlayer?.release()
                mediaPlayer = null
            }
        } catch (e:Exception){
            tuoBotListener.onEvent(
                TuobotEvent(
                    EventType.EVENT_TTS_ERROR,
                    emptyBundle
                )
            )
        }
    }
}
